/*
 * history.c
 *
 *  Created on: Apr 11, 2012
 *      Author: root
 */

/*
 * serv.c
 *
 *  Created on: Apr 4, 2012
 *      Author: root
 */


/*

// include fig01
#include	"unp.h"

#define FD_SETSIZE2	5
#define IDSIZE 20

char* CONNECT_STRING = "230 User logged in\r\n\r\n";
char* QUIT_STRING = "221 Service closing\r\n\r\n";
char* SYNTAX_ERR_STRING = "500 Syntax error, command unrecognized\r\n\r\n";
char* LOG_ERR_STRING = "530 Not logged in\r\n\r\n";

int num_chat = 0;
//int client[FD_SETSIZE2];

typedef struct buffer {
	int read_cnt;
	char *read_ptr;
	char *read_buf;
} ReadBuffer;
typedef struct user {
	int sock;
	char userid[IDSIZE];
	char *line;
	ReadBuffer readBuffer;
} data;

ssize_t my_read(int fd, char *ptr, ReadBuffer *readBuffer);
ssize_t readcrlf_r(int fd, char *vptr, size_t maxlen, ReadBuffer *readBuffer);
char* space_remover(char* dst, char* src, size_t srclen);

void removecli(int s);
void addcli(int s, struct sockaddr_in* newcliaddr);

int main(int argc, char **argv) {
	int i, j, maxi, maxfd, listenfd, connfd, sockfd;
	int nready;

	ssize_t n;
	fd_set rset, allset;
	char buf[MAXLINE];

	char parsing[MAXLINE];
	char parsing2[MAXLINE];
	socklen_t clilen;
	struct sockaddr_in cliaddr, servaddr;

	char id[IDSIZE];
	char message[MAXLINE];
	char fromid[IDSIZE];
	char toid[IDSIZE];

	char* p1;
	char* p2;

	char* msg;
	char protocol[MAXLINE];

	int id_setting = 0;

	data userdata[FD_SETSIZE2];

	ReadBuffer* rdbuf_p;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);

	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

	Listen(listenfd, LISTENQ);

	maxfd = listenfd; // initialize
	maxi = -1; // index into client[] array

//	for (i = 0; i < FD_SETSIZE2; i++) // FD_SETSIZE = 5
//		client[i] = -1; // -1 indicates available entry

	for (i = 0; i < FD_SETSIZE2; i++) // FD_SETSIZE = 5
		userdata[i].sock = -1; // -1 indicates available entry

	FD_ZERO(&allset);
	FD_SET(listenfd, &allset);
// end fig01

// include fig02
	for (;;) {
		memset(buf, 0x00, MAXLINE);
		memset(parsing, 0x00, MAXLINE);
		memset(message, 0x00, MAXLINE);

		rset = allset; // structure assignment

		nready = Select(maxfd + 1, &rset, NULL, NULL, NULL);

		if (FD_ISSET(listenfd, &rset)) { // new client connection
			clilen = sizeof(cliaddr);
			connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
#ifdef	NOTDEF
			printf("new client: %s, port %d\n",
					Inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),
					ntohs(cliaddr.sin_port));
#endif

			//////////////////// USER Login/////////////////////////////

			read(connfd, id, sizeof(id));
			num_chat++;
			Writen(connfd, CONNECT_STRING, strlen(CONNECT_STRING));

			p1 = strtok(id, " \r"); // p is "USER"
			if (strstr(p1, "USER") != NULL) {
				p1 = strtok(NULL, " \r"); // p is ID
			}
			sprintf(id, "%s", p1);
			printf("connected %d people, %s is connect\n", num_chat, id);

			for (i = 0; i < FD_SETSIZE2; i++)
				if (userdata[i].sock < 0) {
					userdata[i].sock = connfd; // save descriptor
					break;
				}

			if (i == FD_SETSIZE2)
				err_quit("too many clients");

			strcpy(userdata[i].userid, id);

			printf("%d socket save in %d \n", connfd, i);

			userdata[i].line = malloc(MAXLINE);

			rdbuf_p = &userdata[i].readBuffer;

			rdbuf_p->read_cnt = 0;
			rdbuf_p->read_buf = malloc(MAXLINE);

			///////////////USER Login/////////////////////
			///////////////////////////////////////////////

			FD_SET(connfd, &allset);
			// add new descriptor to set
			if (connfd > maxfd)
				maxfd = connfd; // for select
			if (i > maxi)
				maxi = i; // max index in client[] array

			if (--nready <= 0)
				continue; // no more readable descriptors

		}

		/////////////////////////////////////////////////////

		for (i = 0; i <= maxi; i++) { // check all clients for data
			memset(buf, 0x00, MAXLINE);

			if ((sockfd = userdata[i].sock) < 0)
				continue;
			if (FD_ISSET(sockfd, &rset)) {
				if ((n = readcrlf_r(sockfd, userdata[i].line, MAXLINE, rdbuf_p))
						== 0) {
					printf("EOF\n");
					memset(userdata[i].line, 0x00, MAXLINE);
					continue;
					//4connection closed by client
					Close(sockfd);
					FD_CLR(sockfd, &allset);
					userdata[i].sock = -1;
				} else {
					memset(parsing, 0x00, MAXLINE);
					memset(protocol, 0x00, MAXLINE);

					printf("recv : [%s]\n", userdata[i].line);
					Writen(sockfd, userdata[i].line, n);

					// message check

//					 strcpy(parsing, userdata[i].line);

					p1 = space_remover(parsing, userdata[i].line,
							strlen(userdata[i].line));
					//printf("protocol [%s]\n", parsing);

					if (strstr(parsing, "QUIT") != NULL) {
						printf("quit!!!\n");
						Writen(userdata[i].sock, QUIT_STRING,
								strlen(QUIT_STRING));
						close(userdata[i].sock);
						num_chat--;
						printf("one has been left\n");

						//removecli(i);
					} else if (strstr(parsing, "WHO") != NULL) {
						printf("user list : \n");
						for (j = 0; j <= maxi; j++) {
							if (!(userdata[j].sock < 0))
								printf("%s\n", userdata[j].userid);
						}
					} else if (strstr(parsing, "FROM") != NULL) {

						p1 = space_remover(fromid, p1, strlen(p1)); //ID1
						//printf("ID1 = [%s]\n", fromid);
						p1 = space_remover(parsing, p1, strlen(p1)); //TO

						//printf("parsing = [%s]\n", parsing);
						p1 = space_remover(toid, p1, strlen(p1)); //ID2

						//printf("ID2 = [%s]\n", toid);

						id_setting = 1;
					} else {
						if (id_setting == 1) {

							sprintf(protocol,
									"299 Message delivered\r\nFROM %s TO %s\r\n%s\r\n\r\n",
									fromid, toid, userdata[i].line);
							printf("send = [%s]\n", protocol);

							for (j = 0; j < num_chat; j++)
								if (!strcmp(userdata[j].userid, toid))
									break;

							Writen(userdata[j].sock, protocol,
									strlen(protocol));
							id_setting = 0;
						} else {
							printf("error\n"); // syntax error
							Writen(userdata[i].sock, SYNTAX_ERR_STRING,
									strlen(SYNTAX_ERR_STRING));
						}

					}

					// send all
					//	 for (j = 0; j <= maxi; j++) {
					//		 if (i != j)
					//		 Writen(client[j], buf, n);
					//	 }
					//Writen(fileno(stdout), buf, n);
					//printf("%s", buf);
					//Writen(sockfd, buf, n);
				}

				if (--nready <= 0)
					break; // no more readable descriptors
			}
		}
	}
}

ssize_t my_read_r(int fd, char *ptr, ReadBuffer *readBuffer) {

	if (readBuffer->read_cnt <= 0) {
		again: if ((readBuffer->read_cnt = read(fd, readBuffer->read_buf,
				sizeof(readBuffer->read_buf))) < 0) {
			if (errno == EINTR)
				goto again;
			return (-1);
		} else if (readBuffer->read_cnt == 0)
			return (0);
		readBuffer->read_ptr = readBuffer->read_buf;
	}

	readBuffer->read_cnt--;
	*ptr = *(readBuffer->read_ptr)++;

	return (1);
}

ssize_t readcrlf_r(int fd, char *vptr, size_t maxlen, ReadBuffer *readBuffer) {
	char *bufx = vptr;
	int rc;
	char c;
	char lastc = 0;

	while (maxlen > 0) {
		if ((rc = my_read_r(fd, &c, readBuffer)) != 1) {
			if (rc < 0 && errno == EINTR)
				continue;
			//printf("[[[[[[[[[[[[[[[[[[[[n=%d]]]]]]]]]]]]]]\n", rc);
			return rc;
		}
		if (c == '\n') {
			if (lastc == '\r')
				vptr--;
			*vptr = '\0';

			//printf("[[[[[[[[[[[[[[[[[[[[n=%d]]]]]]]]]]]]]]\n", vptr - bufx);
			return vptr - bufx;
		}
		*vptr++ = c;
		lastc = c;
		maxlen--;
	}
	return -1;
}

char* space_remover(char* dst, char* src, size_t srclen) {

	size_t n;
	char c;
	char* start = src;
	char* end = src;
	int i = 0;

	for (n = 1; n <= srclen; n++) {
		if ((*src == ' ') || (*src == '\n')) {
			src++;
			continue;
		} else {
			while ((*src != ' ') && (*src != '\n') && (*src != 0)) {
				*dst++ = *src;
				src++;
				end = src;
				n++;
			}
			*dst = 0;
			break;
		}
	}
	return end;
}

//void addcli(int s, struct sockaddr_in* newcliaddr) {
//	char buf[20];
//	inet_ntop(AF_INET, &newcliaddr->sin_addr, buf, sizeof(buf));
//	printf("new client : %s\n", buf);
//	client[num_chat] = s;
//	num_chat++;
//}

//
//void removecli(int s) {
//	int i;
//	for (i = 0; i < FD_SETSIZE2; i++) {
//		if (userdata[i].sock == client[s])
//			break;
//		userdata[i] = userdata[num_chat - 1];
//
//		close(client[s]);
//		if (s != num_chat - 1) {
//			client[s] = client[num_chat - 1];
//		}
//		num_chat--;
//		printf("one has been left\n");
//	}
//}
*/

